﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Algobox.JuicyLib.IO.CSV;
using System.IO;
using Algobox.JuicyLib.SQL.LiquidView;
using Algobox.JuicyLib.Net.FTP;

namespace Algobox.JuicyLib.Apps.Sterling
{
    public class SterlingTradeImporter2 : IDisposable
    {
        /// <summary>
        /// Import trades from Sterling trade file dumps
        /// </summary>
        /// <param name="processname">Name of the executing process</param>
        /// <param name="hostname">Host name that identifies the trades in the database</param>
        /// <param name="dbConnection">Connection string to access the LiquidViewLinqDataContext</param>
        public SterlingTradeImporter2(string processname, string archiveDir, string dbConnection)
        {
            ArchiveDirectory = archiveDir;
            PROCESSNAME = processname;
            DBCON = dbConnection;

            ImporterStocks = new SterlingDailyStockFile(this);
            ImporterOptions = new SterlingDailyOptionsFile(this);

            LiquidViewLinq = new Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext(DBCON);
            LiquidViewHelper.LiquidViewLinq = LiquidViewLinq;
        }

        readonly string PROCESSNAME = "SterlingReportImporter";
        readonly string HOSTNAME = "Sterling-" + DateTime.Now.Year;
        readonly string DBCON;

        public string ArchiveDirectory { get; set; }
        public Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext LiquidViewLinq { get; private set; }
        public string ProcessName { get { return PROCESSNAME; } }
        public string HostName { get { return HOSTNAME; } }
        public SterlingDailyStockFile ImporterStocks { get; private set; }
        public SterlingDailyOptionsFile ImporterOptions { get; private set; }
        public Dictionary<string, string> AccountExchangeMap { get; private set; }
        public List<string> ExchangeBrokerCodes { get; private set; }

        public void Dispose()
        {
            LiquidViewLinq.Dispose();
        }


        public void RunDailyFiles(
            string destinationUri,
            string username,
            string password,
            List<string> ignoreAccounts,
            List<string> stockFiles,
            List<string> optionsFiles,
            Dictionary<string, string> accountExchangeMap,
            List<string> exchangeBrokerCodes)
        {

            List<string> files;
            JuicyFTP ftp = new JuicyFTP(username, password, destinationUri, JuicyFTP.FTPMode.Windows, JuicyFTP.FTPCommand.Passive);

            if (!ftp.TryGetFileList(out files))
            {
                Console.WriteLine("Failed to load file list from " + destinationUri);
                LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to load file list from " + destinationUri, null);
                return;
            }

            AccountExchangeMap = accountExchangeMap;
            ExchangeBrokerCodes = exchangeBrokerCodes;

            using (WebClient client = new WebClient())
            {
                client.Credentials = new NetworkCredential(username, password);

                // get a list of all imported files from the database
                List<string> importedFiles = LiquidViewLinq.LogsFileImports.Where(a => a.LogSource == PROCESSNAME).Select(a => a.Filename).ToList();

                foreach (string filename in files)
                {
                    try
                    {
                        // ignore files already imported
                        if (importedFiles.Contains(filename))
                            continue;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Failed to check LogsFileImports for existing file - " + e.Message);
                        LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to check LogsFileImports for existing file - " + e.Message, null);
                        continue;
                    }

                    // are we dealing with a stock file?
                    if (stockFiles.Any(a => filename.Contains(a)))
                    {
                        Console.WriteLine("Importing new stock trade file " + filename);
                        string file = String.Empty;
                        try
                        {
                            byte[] data = client.DownloadData(destinationUri + filename);
                            file = System.Text.Encoding.ASCII.GetString(data);

                            try
                            {
                                if (!ImporterStocks.ImportStockFile(filename, file, ignoreAccounts))
                                {
                                    Console.WriteLine("Failed to import stock file '" + filename + "' from " + destinationUri + "\r\n");
                                    LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to import stock file '" + filename + "' from " + destinationUri, null);
                                }

                                LogsFileImport row = new LogsFileImport()
                                {
                                    LogSource = PROCESSNAME,
                                    Filename = filename,
                                    TimeStamp = DateTime.Now
                                };
                                LiquidViewLinq.LogsFileImports.InsertOnSubmit(row);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("Failed to import stock file '" + filename + "' from " + destinationUri + "\r\n" + e);
                                LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to import stock file '" + filename + "' from " + destinationUri + " - " + e, null);
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Failed to download stock file '" + filename + "' from " + destinationUri + "\r\n" + e);
                            LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to download stock file '" + filename + "' from " + destinationUri + " - " + e, null);
                        }
                    }
                    // or an options files?
                    else if (optionsFiles.Any(a => filename.Contains(a)))
                    {
                        Console.WriteLine("Importing new options trade file " + filename);
                        string file = String.Empty;
                        try
                        {
                            byte[] data = client.DownloadData(destinationUri + filename);
                            file = System.Text.Encoding.ASCII.GetString(data);

                            try
                            {
                                if (!ImporterOptions.ImportOptionsFile(filename, file, ignoreAccounts))
                                {
                                    Console.WriteLine("Failed to import options file '" + filename + "' from " + destinationUri + "\r\n");
                                    LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to import options file '" + filename + "' from " + destinationUri, null);
                                }

                                LogsFileImport row = new LogsFileImport()
                                {
                                    LogSource = PROCESSNAME,
                                    Filename = filename,
                                    TimeStamp = DateTime.Now
                                };
                                LiquidViewLinq.LogsFileImports.InsertOnSubmit(row);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("Failed to import options file '" + filename + "' from " + destinationUri + "\r\n" + e);
                                LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to import options file '" + filename + "' from " + destinationUri + " - " + e, null);
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Failed to download options file '" + filename + "' from " + destinationUri + "\r\n" + e);
                            LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Failed to download options file '" + filename + "' from " + destinationUri + " - " + e, null);
                        }

                    }
                    else
                    {
                        // filter file name you don't want
                        if (!filename.Contains("htaccess"))
                        {
                            Console.WriteLine("Ignoring file '" + filename + "' as it is not mapped to the stock or options file name filters");
                            LiquidViewLinq.ExceptionHandlerThrow(PROCESSNAME, "Ignoring file '" + filename + "' as it was not mapped to the stock or options file name filter", null);
                        }
                    }

                }
            }

            LiquidViewLinq.SubmitChanges();

        }



        public string GetExchangeMIC(string destination)
        {
            switch (destination)
            {
                case "LSE":
                    return "XLON";
                case "BATSCYCLE":
                    return "BATE";
                case "BATSEU":
                    return "BATE";
                case "BATSPP":
                    return "BATE";
                case "BATSRC":
                    return "BATE";
                case "BATSRL":
                    return "BATE";
                case "CHIXEU":
                    return "CHIX";
                case "ARCA":
                case "ARCA=":
                    return "ARCX";
                case "BATS":
                    return "BATS";
                case "NSDQ":
                    return "XNAS";
                case "NYSE":
                    return "XNYS";
                case "CBOE":
                    return "XCBO";
                case "ISE":
                    return "XISX";
                case "AMX":
                    return "AMXO";
                case "NASD":
                    return "XNDQ";
                case "PHLX":
                    return "XPHO";
                case "BOSX":
                    return "XBOS";
                case "PSEX":
                    return "XPSE";
                case "AMEX":
                    return "AMXO";
                case "FBCO":
                    return "FBCO";
                case "GSEU":
                    return "GSEU";
            }
            return "XXXX";
        }

        public string GetExchangeMICfromSymbol(string symbol)
        {
            int index = symbol.LastIndexOf('.');
            string suffix;
            if (index > 0)
                suffix = symbol.Substring(index + 1);
            else
                suffix = "";

            switch (suffix)
            {
                case "LN":
                    return "XLON";
                case "ST":
                    return "XSTO";
                case "AM":
                    return "XASE";
                case "DB":
                    return "XFRA";
                case "BI":
                    return "XMIL";
                case "ZU":
                    return "XSWX";
                case "HS":
                    return "XHEL";
                case "CO":
                    return "XCSE";
                case "MD":
                    return "MTAA";
                case "TO":
                    return "XTSE";
                case "TV":
                    return "XTSX";
                default:
                    return "XNYS";
            }
        }


        public bool CheckDirectory(string directory)
        {
            if (directory == String.Empty)
                return false;

            if (directory[0] == '/')
                directory = directory.Substring(1);

            try
            {
                if (Directory.Exists(directory))
                    return true;

                Directory.CreateDirectory(directory);
                return true;
            }
            catch (Exception e)
            {
                LiquidViewHelper.LogException(PROCESSNAME, "Create directory failed for " + directory + " with Exception : " + e.Message);
                return false;
            }
        }

        internal void GetFlagSettings(string exchange, string flag, out bool isAggressor, out string routedMIC)
        {
            if (exchange == "ARCX")
            {
                switch (flag)
                {
                    case "X":
                        routedMIC = "XXXX";
                        isAggressor = false;
                        return;
                    case "R":
                        isAggressor = true;
                        routedMIC = null;
                        return;
                    case "F":                    
                        isAggressor = false;
                        routedMIC = "XNYS";
                        return;
                    case "N":
                    case "C":
                    case "W":
                        isAggressor = true;
                        routedMIC = "XNYS";
                        return;
                    default:
                        isAggressor = false;
                        routedMIC = null;
                        return;
                }
            }
            else if (exchange == "BATS" || exchange == "BATE" || exchange == "CHIX")
            {
                switch (flag)
                {
                    case "X":
                        routedMIC = "XXXX";
                        isAggressor = false;
                        return;
                    case "R":
                        isAggressor = true;
                        routedMIC = null;
                        return;
                    default:
                        isAggressor = false;
                        routedMIC = null;
                        return;
                }
            } 
            else if (exchange == "XNAS")
            {
                switch (flag)
                {
                    case "X":
                    case "Y":
                    case "S":
                    case "U":
                    case "P":
                        routedMIC = "XXXX";
                        isAggressor = false;
                        return;
                    case "R":
                    case "C":
                    case "H":
                        isAggressor = true;
                        routedMIC = null;
                        return;
                    case "F":
                    case "G":               
                        isAggressor = true;
                        routedMIC = "XNYS";
                        return;
                    default:
                        isAggressor = false;
                        routedMIC = null;
                        return;
                }
            }
            else if (exchange == "XNYS")
            {
                switch (flag)
                {
                    case "1":
                    case "4":
                    case "5":
                    case "6":
                    case "7":
                        isAggressor = true;
                        routedMIC = null;
                        return;
                    case "2":
                    case "9":
                        isAggressor = false;
                        routedMIC = null;
                        return;
                    default:
                        routedMIC = "XXXX";
                        isAggressor = false;
                        return;
                }
            }
            else if (exchange == "XLON")
            {
                switch (flag)
                {
                    case "1":
                    case "2":
                    case "4":
                    case "R":
                        isAggressor = true;
                        routedMIC = null;
                        return;
                    default:
                        isAggressor = false;
                        routedMIC = null;
                        return;
                }
            }

            isAggressor = false;
            routedMIC = null;
            return;
        }
    }
}
